#include "sceneobject.h"

USING_NAMESPACE_OXGE


//texture channel
Vector2& TextureChannel::GetFaceVertexCoord( int iface, int ivertex )
{
	int texidx = m_vTexFaces[iface][ivertex];
	return m_vTexCoords[texidx];
}

const Vector2& TextureChannel::GetFaceVertexCoord( int iface, int ivertex ) const
{
	int texidx = m_vTexFaces[iface][ivertex];
	return m_vTexCoords[texidx];
}

TextureChannel::TextureChannel()
{
	pTexture = NULL;
	m_vTexCoords.push_back(Vector2::ZERO);
}

//scene Object
SceneObject& SceneObject::RefreshNorms()
{
	if( m_normMode == NormPerVertex )
		RefreshNormsPerVertex();
	if( m_normMode == NormPerFace )
		RefreshNormsPerFaces();

	return *this;
}

void SceneObject::RefreshNormsPerVertex()
{
	m_vNormPerVertex.clear();
}

void SceneObject::RefreshNormsPerFaces()
{
	m_vNormPerFace.clear();
	m_vNormPerFace.reserve(m_vFaces.size());

	for(int i=0;i<(int)m_vFaces.size();++i)
	{
		Vector3Index& face = m_vFaces[i];
		Vector3 v1 = m_vVertexs[face[1]] - m_vVertexs[face[0]];
		Vector3 v2 = m_vVertexs[face[2]] - m_vVertexs[face[1]];
		m_vNormPerFace.push_back(v1.cross(v2).Normalize());			
	}
	
}


static bool IsFaceIndexValid(const Vector3Index& face, int vertexCount)
{
	return face[0] < vertexCount&& face[1] < vertexCount&& face[2] < vertexCount;
}

//check faces valid
bool SceneObject::IsFacesValid() const
{
	int vertexCount = (int)m_vVertexs.size();
	for(int i=0;i< (int)m_vFaces.size();++i)
	{		
		if( IsFaceIndexValid(m_vFaces[i], vertexCount) ) 
			continue;
		else 
			return false;
	}
	return true;
}

bool SceneObject::TryFixFaces()
{
	Vector3IndexArray oldFaces = m_vFaces;
	m_vFaces.clear();
	for(int i=0;i<(int)oldFaces.size();++i)
	{
		if( IsFaceIndexValid(oldFaces[i], m_vVertexs.size() ) )
			m_vFaces.push_back(oldFaces[i]);
	}
	return true;
}

bool SceneObject::IsValid() const
{
	if( !IsFacesValid() )
		return false;

	if( !IsNormsValid()) 
		return false;

	for(int i=0;i<(int)m_vTextureChannels.size(); ++i)
	{
		if(!IsTextureChannelValid(i))
			return false;
	}

	return true;
}

bool SceneObject::TryFix()
{
	if( !TryFixFaces() )
		return false;
	
	if( !TryFixNorms())
		return false;

	for(int i=0;i<(int)m_vTextureChannels.size(); ++i)
	{
		if(!TryFixTextureChannel(i))
			return false;
	}

	return true;

}

bool SceneObject::IsNormsValid() const
{
	if( GetNormMode() == NormPerFace )
	{
		return m_vNormPerFace.size() == m_vFaces.size();
	}
	if( GetNormMode() == NormPerVertex )
	{
		return m_vNormPerVertex.size() == m_vVertexs.size();
	}
	return false;
}

bool SceneObject::TryFixNorms()
{
	if(!IsNormsValid())
		RefreshNorms();
	return IsNormsValid();
}

bool SceneObject::IsTextureChannelValid( int idx ) const
{
	assert((int)m_vTextureChannels.size() > idx);
	const TextureChannel& theChannel = m_vTextureChannels[idx];
	
	if(theChannel.m_vTexFaces.size() != m_vFaces.size() )
		return false;

	//check every face tex coord index is valid
	for(int i=0;i< (int)theChannel.m_vTexFaces.size(); ++i)
	{
		const Vector3Index& faceTexIndex = theChannel.m_vTexFaces[i];
		if( !IsFaceIndexValid(faceTexIndex, theChannel.m_vTexCoords.size()) )
			return false;	
	}
	return true;
}

bool SceneObject::TryFixTextureChannel( int idx )
{
	assert((int)m_vTextureChannels.size() > idx);
	TextureChannel& theChannel = m_vTextureChannels[idx];
	//face count not same
	if( theChannel.m_vTexFaces.size() != m_vFaces.size() )
	{		
		theChannel.m_vTexFaces.resize( m_vFaces.size(),Vector3Index(0,0,0) );
	}
	//text face index not valid
	for(int i=0;i< (int)theChannel.m_vTexFaces.size(); ++i)
	{
		Vector3Index& faceTexIndex = theChannel.m_vTexFaces[i];
		if( !IsFaceIndexValid(faceTexIndex, theChannel.m_vTexCoords.size()) )
		{		
			faceTexIndex = Vector3Index(0,0,0);
		}
	}
	return true;
}

SceneObject::SceneObject()
{
	m_normMode = NormPerFace;
}

void SceneObject::RefreshBoundingBox()
{

}